﻿.486
porta equ 3c0h
portb equ 3c4h
portc equ 3c8h
ctrl equ  3cch
code segment use16
assume cs:code
        org 2000h
        jmp start
disptab db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh
        db  6fh,77h,7ch,39h,5eh,79h,71h
kettab  db  0eeh,0edh,0ebh,0e7h,0deh,0ddh
        db  0dbh,0d7h,0beh,0bdh,0bbh,0b7h
        db  07eh,07dh,07bh,077h
num     db   1   ;后续每次位移数
;待实现的功能：按下1-3 选择亮灯个数
;             按下4-7 选择小灯方向  
;              按下 8 9 A选择速度（延时实现）
;          A口接左边8小灯   B口接右边8
;-------------pc0-pc3  :key_p0-p3
;---------------pc4-pc7:Q0-Q3
; di用于延时函数
;8255配置为 A 输出 B 输出 C低四位输入&高四位输出
start:  mov cx,0f000h
        mov di,0ffffh ;设置默认延时时间为0f000h,默认小灯全灭,默认每次位移一个灯
        mov dx,ctrl
        mov si,1
        mov al,81h
        out dx,al
        ;上面用于初始化8255以及延时器
        mov dx,portb
        mov al,00h
        out dx,al
t2:     mov al,00h
        mov dx,portc
        out dx,al
        mov dx,portc
loop1:  in  al,dx
        and al,0fh
        cmp al,0fh
        je  loop1
        mov bh,al          ;bh保存列
        call    delay      
        mov al,0efh
        mov bl,al
loop2:  mov dx,portc
        out dx,al
        mov dx,portc
        in  al,dx
        and al,0fh         ;bl高四位为行
        cmp al,0fh
        jne loop3
        rol bl,1
        mov al,bl   
        jmp loop2
loop3:  
        and bl,0f0h       
        or  bl,bh
        call    delay
        push  si
        lea si,kettab
       mov  bh,0
loop4:  mov al,[si]
        cmp al,bl
        je  loop5
        inc bh
        inc si
        jmp loop4
;至此完成了对输入按键的读取，输入按键保存在bh当中
;在loop5中可以实现对应功能:

;待实现的功能：按下1-3 选择亮灯个数   
;             按下4-7 选择小灯方向  
;              按下 8 9 A选择速度（延时实现） 8->慢 9->中  A->快
;               按下E结束
loop5:  pop si
        cmp bh,01h ;按下1 
        jz  func_one   
        cmp bh,02h ;按下2
        jz  func_two  
        cmp bh,03h ;按下3 
        jz  func_three   
        cmp bh,04h ;按下4
        jz  func_four  
        cmp bh,05h ;按下5
        jz  func_five   
        cmp bh,06h ;按下6
        jz  func_six   
        cmp bh,07h ;按下7 
        jz  func_siven  
        cmp bh,08h ;按下8 
        jz  func_eight  
        cmp bh,09h ;按下9
        jz  func_nine  
        cmp bh,0ah ;按下A
        jz  func_a  
        cmp bh,0eh ;按下1 
        jz  func_e
        ;如果按到其他键，则回到开始重新读
        jmp t2
;数量选择函数
func_one:   mov     num,1
            call    f_main
            jmp t2
func_two:   
            mov     num,2
            call    f_main
            jmp t2
func_three:   
            mov     num,3
            call    f_main
            jmp t2
;下面为方向选择函数一（从左往右）  方向选择要根据数量给对应的初始值di
func_four:   cmp     num,1
            je      func_four_one
            cmp     num,2
            je      func_four_two
            cmp     num,3
            je      func_four_three
func_four_one:   mov     di,0111111111111111b
            call    f_main
            jmp t2
func_four_two:   mov     di,0011111111111111b
            call    f_main
            jmp t2
func_four_three:   mov     di,0001111111111111b
            call    f_main
            jmp t2
;下面为方向选择函数二（从右往左）   方向选择要根据数量给对应的初始值di
func_five:   cmp     num,1
            je      func_five_one
            cmp     num,2
            je      func_five_two
            cmp     num,3
            je      func_five_three
func_five_one:   mov     di,1111111111111110b
                 mov     num,15
                 call    f_main
                 jmp t2
func_five_two:   mov     di,1111111111111100b
                 mov     num,14
                 call    f_main
                 jmp     t2
func_five_three:   mov     di,1111111111111000b
                   mov     num,13
                   call    f_main
                   jmp     t2
;下面为方向选择函数三（从中间往两边）即分别左移   方向选择要根据数量给对应的初始值di
func_six:   cmp     num,1
            je      func_six_one
            cmp     num,2
            je      func_six_two
            cmp     num,3
            je      func_six_three
func_six_one:   mov     di,1111111011111110b
                mov     num,15
            call    f_main
            jmp t2
func_six_two:   mov     di,1111110011111100b
                 mov     num,14
            call    f_main
            jmp t2
func_six_three:   mov     di,1111100011111000b
                 mov     num,13
            call    f_main
            jmp t2
;下面为方向选择函数四（从两边往中间）即分别右移   方向选择要根据数量给对应的初始值di
func_siven:   cmp     num,1
            je      func_siven_one
            cmp     num,2
            je      func_siven_two
            cmp     num,3
            je      func_siven_three
func_siven_one:   mov     di,0111111101111111b
            call    f_main
            jmp t2
func_siven_two:   mov     di,0011111100111111b
            call    f_main
            jmp t2
func_siven_three:   mov     di,0001111100011111b
            call    f_main
            jmp t2
;下面为速度选择函数
func_eight:   call    delay_short
        jmp t2
func_nine:   call    delay_mid
        jmp t2
func_a:   call       delay_long
        jmp t2
;下面为结束函数
func_e:   call    f_e
;下面为对应功能的函数   注：在函数最后需要回到t2循环
;@@@brief:  主函数，每次按键按下都会进入该函数
;@param:   di:亮灯个数、初始状态   si:每次位移次数    
;@return:  无
;@note:    无 
f_main   proc    near
loop_one:       
        MOV     AX,di
        mov     DX,portb
        out     DX,AL
        SHR     AX,8
        mov     DX,porta
        out     DX,AL
        call    delay
        ;上面完成了亮1个灯的功能,下面开始向右移位
        push     cx
        mov     cl,num
        ror     di,cl
        pop     cx
        MOV     AX,di
        mov     DX,portb
        out     DX,AL
        SHR     AX,8
        mov     DX,porta
        out     DX,AL ;检测是否按键改变
        CALL    delay
        push     cx
        mov     cl,num
        ror     di,cl
        pop     cx    ;向右移位

        mov al,00h
        mov dx,portc
        out dx,al
        mov dx,portc
        in  al,dx
        and al,0fh
        cmp al,0fh
        jz   loop_one                                   ;如果出现bug有可能是延迟函数里面ax寄存器出问题了？
        ret
f_main  endp

;按下e；所有灯亮灭三次熄灭
f_e  proc    near
        call    delay_long
        MOV     DX,portb
        MOV     AL,00h
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,00h
        OUT     DX,AL
        CALL    delay
        
        MOV     DX,portb
        MOV     AL,0ffh
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,0ffh
        OUT     DX,AL
        CALL    delay

        MOV     DX,portb
        MOV     AL,00h
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,00h
        OUT     DX,AL
        CALL    delay

        MOV     DX,portb
        MOV     AL,0ffh
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,0ffh
        OUT     DX,AL
        CALL    delay

        MOV     DX,portb
        MOV     AL,00h
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,00h
        OUT     DX,AL
        CALL    delay

        MOV     DX,portb
        MOV     AL,0ffh
        OUT     DX,AL
        MOV     DX,porta
        MOV     AL,0ffh
        OUT     DX,AL
        CALL    delay

        MOV  AH, 4CH   ;这里可能有问题，需要debug
        INT  21h
        ret
f_e   endp
;下面为延时函数  具体延时时间放在cx寄存器，方便进行修改
;在亮灯循环中的调用只会修改cx寄存器的值
;亮灯过程中只会调用delay，默认延时时间为0f000h
delay_long   proc    near
        mov cx,0ffffh
        ret
delay_long  endp

delay_mid   proc    near
        mov cx,7fffh
        ret
delay_mid  endp

delay_short   proc    near
        mov cx,0f00h
        ret
delay_short  endp

delay   proc    near
        push    ax
        mov     ax,cx
dlp:    loop    dlp
        mov     cx,ax
        pop      ax
        ret
delay  endp


code    ends
end start

